/**
* file sci.c
* author Li Yuan
* platform: mc9s12XX
* date: 2012-7-22
* version: 1.0.1
* description: SCI(Serial Communication Interface) Support Code
*/
 
#include "derivative.h"      /* derivative-specific definitions */
#include "sci.h"
 
 /**
 * @brief   initialize the SCI0 module
 */
void SCIInit (void)
{ 
    SCISetWorkMode(SCI0, NORMAL_MODE);
    SCISetPowerMode(SCI0, RUN_MODE);
    SCISetDataBit(SCI0, 8);
    SCISetParity(SCI0, 0, 0);
    SCISetBaudRate(SCI0, 9600, 16384000L); // 16M Clock
    SCIEnableRecv(SCI0, 1);
    SCIEnableTrans(SCI0, 1);  
}
 
/**
 * Set the Baud Rate of the SCI.
 * @param  port, port can be SCI0 / SCI1
 * @param  baudRate, the wanted baud rate.
 * @param  busClk, The SCI module clock.
 */
void SCISetBaudRate (unsigned char port, unsigned long baudRate, unsigned long busClk)
{
    unsigned short baudRateReg;
    baudRateReg = (unsigned short) (busClk / baudRate / 16);       // Or it can be wrote as ...
    //baudRateReg = (busClk / baudRate) >> 4;
    if (port == SCI0)
    {  
        // Here we must write BDH first!
        SCI0BDH =  ( 0x1f & (baudRateReg >> 8) );
        SCI0BDL =  (0xff & baudRateReg);
    }
    else if(port == SCI1)
    {
        SCI1BDH =  ( 0x1f & (baudRateReg >> 8) );
        SCI1BDL =  (0xff & baudRateReg);
    }
    else
    {
        // Something must go wrong. Do nothing here!  
    }
}
 
 
/**
 * Set the Interrupt Enable Bit
 * @param  port  port can be SCI0 / SCI1
 * @param  tie   Transmitter Interrupt Enable BIt
 * @param  tcie  Transmission Complete Interrupt Enable BIt
 * @param  rie   Receiver Full Interrupt Enable BIt
 * @param  ilie  Idle Line Interrupt Enable BIt
 *                0 Interrupt requests Disabled
 *                1 Interrupt requests Enabled
 */
/*
void SCISetIEBit (unsigned char port, unsigned char tie, unsigned char tcie, unsigned char rie, unsigned char ilie)
{
    if (port == SCI0)
    {  
        SCI0CR2_SCTIE = (tie & 0x01);
        SCI0CR2_TCIE = (tcie & 0x01);
        SCI0CR2_RIE = (rie & 0x01);
        SCI0CR2_ILIE = (ilie & 0x01);
    }
    else if(port == SCI1)
    {
        SCI1CR2_SCTIE = (tie & 0x01);
        SCI1CR2_TCIE = (tcie & 0x01);
        SCI1CR2_RIE = (rie & 0x01);
        SCI1CR2_ILIE = (ilie & 0x01);
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
     
}   
*/
 
/**
 * Set the Interrupt Enable Bit
 * @param  port  port can be SCI0 / SCI1
 * @param  ie    Interrupt Enable BIt
 *               SCI_TIE,  Transmitter Interrupt Enable
 *               SCI_TCIE, Transmission Complete Interrupt Enable
 *               SCI_RIE,  Receiver Full Interrupt Enabl
 *               SCI_ILIE, Idle Line Interrupt Enable
 */
void SCISetIEBit (unsigned char port, unsigned char ie)
{
    unsigned char cr2;
    ie &= 0xf0;
    if (port == SCI0)
    {  
        cr2 = SCI0CR2;
        cr2 &= 0x0f; // 清除所有中断使能位
        cr2 |= ie;
        SCI0CR2 = cr2;
    }
    else if(port == SCI1)
    {
        cr2 = SCI1CR2;
        cr2 &= 0x0f; // 清除所有中断使能位
        cr2 |= ie;
        SCI1CR2 = cr2;
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
     
}
/**
 * Enable The Tx interrupt  (Transmitter Interrupt Enable BIt)
 * @param  port, port can be SCI0 / SCI1
 */
void SCIEnableTxInt (unsigned char port)
{
    if (port == SCI0)
    {  
        SCI0CR2_SCTIE = 1;
    }
    else if(port == SCI1)
    {
        SCI1CR2_SCTIE = 1;
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
}
 
/**
 * Disable The Tx interrupt  (Transmitter Interrupt Enable BIt)
 * @param  port, port can be SCI0 / SCI1
 */
void SCIDisTxInt(unsigned char port)
{
    if (port == SCI0)
    {  
        SCI0CR2_SCTIE = 0;
        //SCI0CR2_TCIE = 0;
    }
    else if(port == SCI1)
    {
        SCI1CR2_SCTIE = 0;
        //SCI1CR2_TCIE = 0;
    }   
}
 
 
/**
 * Enable/Disable SCI Receiver
 * @param port  port can be SCI0 / SCI1
 * @param isEnable  0 disable 1 enable
 */
void SCIEnableRecv (unsigned char port, unsigned char isEnable)
{
    if (port == SCI0)
    {  
        SCI0CR2_RE = (isEnable & 0x01);
    }
    else if(port == SCI1)
    {
        SCI1CR2_RE = (isEnable & 0x01);
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
     
}
 
/**
 * Enable/Disable SCI Transmitter
 * @param port      port can be SCI0 / SCI1
 * @param isEnable  0 disable 1 enable
 */
void SCIEnableTrans (unsigned char port, unsigned char isEnable)
{
    if (port == SCI0)
    {  
        SCI0CR2_TE = (isEnable & 0x01);
    }
    else if(port == SCI1)
    {
        SCI1CR2_TE = (isEnable & 0x01);
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
     
}
 
/**
 * Set the Idle Line Type
 * @param port  port can be SCI0 / SCI1
 * @param type  0 Idle char bit count begins after start bit
 *              1 Idle char bit count begins after stop bit
 */
void SCISetIdleLineType (unsigned char port, unsigned char type)
{
    if (port == SCI0)
    {  
        SCI0CR1_ILT = (type & 0x01);
    }
    else if(port == SCI1)
    {
        SCI1CR1_ILT = (type & 0x01);
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
     
}
 
 
/**
 * Set the Wakeup Condition.
 * @param port      port can be SCI0 / SCI1
 * @param condi     0 for Idle line wakeup, 1 for address mark wakeup
 */
void SCISetWakeupCondi (unsigned char port, unsigned char condi)
{
    if (port == SCI0)
    {  
        SCI0CR1_WAKE = (condi & 0x01);
    }
    else if(port == SCI1)
    {
        SCI1CR1_WAKE = (condi & 0x01);
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
     
}
 
/**
 * Enable/Disable parity function and set the Parity type
 * @param port port can be SCI0 / SCI1
 * @param isEnable 0 for disable parity function, 1 for enable
 * @param type 0 for Even Parity, 1 for Odd Parity
 */
void SCISetParity (unsigned char port, unsigned char isEnable, unsigned char type)
{
    if (port == SCI0)
    {  
        SCI0CR1_PE = (isEnable & 0x01);
        SCI0CR1_PT = (type & 0x01);
    }
    else if(port == SCI1)
    {
        SCI1CR1_PE = (isEnable & 0x01);
        SCI1CR1_PT = (type & 0x01);
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
     
}
 
/**
 * Set the Data Format Mode Bit
 * @param port port can be SCI0 / SCI1
 * @param bits must be 8 or 9
 */
void SCISetDataBit (unsigned char port, unsigned char bits)
{
    if (port == SCI0)
    {  
        switch(bits)
        {
            case 8:
                SCI0CR1_M = 0;   /* 1 start bit, 8 data bits, 1 stop bit */
                break;
            case 9:
                SCI0CR1_M = 1;   /* 1 start bit, 9 data bits, 1 stop bit */
                break;
            default:
                // If code run here, something must go wrong. Do nothing here!  
                break;
        }
    }
    else if(port == SCI1)
    {
        switch(bits)
        {
            case 8:
                SCI1CR1_M = 0;   /* 1 start bit, 8 data bits, 1 stop bit */
                break;
            case 9:
                SCI1CR1_M = 1;   /* 1 start bit, 9 data bits, 1 stop bit */
                break;
            default:
                // If code run here, something must go wrong. Do nothing here!  
                break;
        }      
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }   
     
}
 
/**
 * Set the work mode of operation
 * @param port port can be SCI0 / SCI1
 * @param mode mode can be NORMAL_MODE / LOOP_MODE / SING_WIRE_MODE
 */
void SCISetWorkMode (unsigned char port, unsigned char mode)
{
    if (port == SCI0)
    {  
        switch(mode)
        {
            case NORMAL_MODE:
                SCI0CR1_LOOPS = 0;
                SCI0CR1_RSRC = 0;
                break;
            case LOOP_MODE:
                SCI0CR1_LOOPS = 1;
                SCI0CR1_RSRC = 0;
                break;
            case SING_WIRE_MODE:
                SCI0CR1_LOOPS = 1;
                SCI0CR1_RSRC = 1;
                break;
            default:
                // If code run here, something must go wrong. Do nothing here!  
                break;
        }
    }
    else if(port == SCI1)
    {
        switch(mode)
        {
            case NORMAL_MODE:
                SCI1CR1_LOOPS = 0;
                SCI1CR1_RSRC = 0;
                break;
            case LOOP_MODE:
                SCI1CR1_LOOPS = 1;
                SCI1CR1_RSRC = 0;
                break;
            case SING_WIRE_MODE:
                SCI1CR1_LOOPS = 1;
                SCI1CR1_RSRC = 1;
                break;
            default:
                // If code run here, something must go wrong. Do nothing here!  
                break;
        }         
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }
}
 
/**
 * Enable/Disable the SCI in wait mode
 * @param port port can be SCI0 / SCI1
 * @param mode mode can be RUN_MODE / WAIT_MODE
 */
void SCISetPowerMode (unsigned char port, unsigned char mode)
{
    if (port == SCI0)
    {  
        switch(mode)
        {
            case RUN_MODE:
                SCI0CR1_SCISWAI = 0;
                break;
            case WAIT_MODE:
                SCI0CR1_SCISWAI = 1;
                break;
            default:
                // If code run here, something must go wrong. Do nothing here!  
                break;
        }
    }
    else if(port == SCI1)
    {
        switch(mode)
        {
            case RUN_MODE:
                SCI1CR1_SCISWAI = 0;
                break;
            case WAIT_MODE:
                SCI1CR1_SCISWAI = 1;
                break;
            default:
                // If code run here, something must go wrong. Do nothing here!  
                break;
        }        
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }
}
 
/**
 * Set the TXDIR ( Only for Single Wire MODE)
 * @param port port can be SCI0 / SCI1
 * @param dir 0 TXD used as input, 1 TXD used as output
 */
void SCISetTXDIR (unsigned char port, unsigned char dir)
{
    if (port == SCI0)
    { 
        SCI0SR2_TXDIR = dir;
    }
    else if(port == SCI1)
    {
        SCI1SR2_TXDIR = dir;
    }
    else
    {
        // If code run here, something must go wrong. Do nothing here!  
    }
       
}
 
 
/**
 * Send a char throungh SCI module.
 * @param port port can be SCI0 / SCI1
 * @param s the data to be sent
 */
void SCIPutChar ( unsigned char port, unsigned char s)
{ 
    if (port == SCI0)
    {  
        while (SCI0SR1_TDRE == 0);   // SCI0SR1_TC 是发送完成
        SCI0DRL = s;
    }
    else
    {
        while (SCI1SR1_TDRE == 0);   // SCI1SR1_TC
        SCI1DRL = s;       
    }
}
 
/**
 * Send a char string throungh SCI module.
 * @param port  port can be SCI0 / SCI1
 * @param *str  the string to be sent
 */
void SCIPutStr (unsigned char port, unsigned char *str)
{
    while (0 != *str)
    {
        SCIPutChar(port, *str);
        str++;
    }
}
 
/**
 * Send a char string throungh SCI module in a safer manner.
 * @param port  port can be SCI0 / SCI1
 * @param *str  the string to be sent
 * @param maxSize the max size of the string  
 */
void SCIPutStr_safe (unsigned char port, unsigned char *str, int maxSize)
{
    while (0 != *str && maxSize > 0)
    {
        SCIPutChar(port, *str);
        str++;
        maxSize --;
    }
}
 
/**
 * Send data throungh SCI module.
 * @param port  port can be SCI0 / SCI1
 * @param *p    pointer to the data to be sent
 * @param size  the size(byte) of the data
 */
void SCIWrite (unsigned char port, void *p, int size)
{
    unsigned char *str = (unsigned char *)p;
    while (size > 0)
    {
        SCIPutChar(port, *str);
        str++;
        size--;
    }
}
 
/**
 * Send a short int value(Big Endian) throungh SCI module.
 * @param port  port can be SCI0 / SCI1
 * @param i     the data to be sent
 */
void SCIPutShortBigEndian (unsigned char port, short i)
{
    char * p = (char *)&i;
    SCIPutChar( port, p[0]);
    SCIPutChar( port, p[1]);
}
 
/**
 * Send a short int value(Little Endian) throungh SCI module.
 * @param port  port can be SCI0 / SCI1
 * @param i     the data to be sent
 */
void SCIPutShortLittleEndian (unsigned char port, short i)
{
    char * p = (char *)&i;
    SCIPutChar( port, p[1]);
    SCIPutChar( port, p[0]);
}
 
/**
 * Send a long int value throungh SCI module.
 * @param port  port can be SCI0 / SCI1
 * @param i     the data to be sent
 */
void SCIPutLongBigEndian (unsigned char port, long i)
{
    char * p = (char *)&i;
    SCIPutChar( port, p[0]);
    SCIPutChar( port, p[1]);
    SCIPutChar( port, p[2]);
    SCIPutChar( port, p[3]);
}
 
/**
 * Send a long int value(Little Endian) throungh SCI module.
 * @param port  port can be SCI0 / SCI1
 * @param i     the data to be sent
 */
void SCIPutLongLittleEndian (unsigned char port, long i)
{
    char * p = (char *)&i;
    SCIPutChar( port, p[3]);
    SCIPutChar( port, p[2]);
    SCIPutChar( port, p[1]);
    SCIPutChar( port, p[0]);
}
 
/**
 * Receive a char data from SCI module,no reply.
 * @param  port port can be SCI0 / SCI1
 * @return the received char
 */
unsigned char SCIGetChar(unsigned char port)
{
    if (port == SCI0)
    { 
        while( SCI0SR1_RDRF == 0);
        return SCI0DRL;
    }
    else
    {
        while( SCI1SR1_RDRF == 0);
        return SCI1DRL;
    }
}
 
/**
 * Receive a char data from SCI module in a safer manner.
 * @param  port port can be SCI0 / SCI1
 * @param  *p the recived char
 * @param  TimeOut timeout value
 * @return 0 is success, 1 is timeout
 */
unsigned char SCIGetChar_Safe(unsigned char port, unsigned char *p, unsigned short TimeOut)
{
    if (port == SCI0)
    { 
        while( SCI0SR1_RDRF == 0 && TimeOut > 0) TimeOut--;
        *p = SCI0DRL;
    }
    else
    {
        while( SCI1SR1_RDRF == 0 && TimeOut > 0) TimeOut--;
        *p = SCI1DRL;
    }
    if( TimeOut == 0) return 0;
    else return 1;
}